import {nextTick} from 'vue'
import {
    calcClass,
    calcStyle,
    calcStyleAndWidth,
    runEvent,
    runExpress,
    evalSetBind,
    evalGetBind
} from '../../utils'
import {getRuntimeCmp} from '../../runtime/CmpStore'
import _ from "lodash";
import VJsonContext from "../../runtime/VJsonContext";
import EventBus from "../../studio/event-bus";

/**
 * 公共混入方法
 */
export default {
    props: {
        vjson: Object as any,
        vcxt: VJsonContext,
        dialogScope: Object as any,
        parentComponent: {type: Object as any, required: false},
        parentList: {type: Array, required: false},
        indexOfParentList: {type: Number, required: false},
    },
    data() {
        let hidden = this.vjson.hidden ?? false

        if (typeof window['$security']?.hasAnyPermissions === 'function' &&
            _.isArray(this.vjson.permissions) &&
            _.size(this.vjson.permissions) > 0) {

            if (!window['$security']?.hasAnyPermissions(...this.vjson.permissions)) {
                hidden = true
            }
        }

        return {
            _destroyed: true,
            hidden: hidden
            // _timeId: _.uniqueId('_time')
        }
    },
    created() {
        // console.time(this._timeId)
        this._destroyed = false
        const reference = this.vjson.reference
        if (reference) {
            // 在模型中挂接实体类
            _.set(this.vcxt.scope.$data, 'refs.' + reference, this)
        }
    },
    mounted() {
        /**
         * 解析所有 bind 中带有的表达式
         * {
         *     value: "{a.b}",      // value 忽略
         *     disabled: "{calcProp1}"  // 解析为 return this.calcProp1
         *     readonly: "return this.calc1 - this.calc2" // 解析为 express 表达式EVAL即可
         * }
         */
        nextTick(() => {
            this.runEvent('afterrender')
        })
        this.stopList = []
        _.forOwn(this.vjson.bind, (express, property) => {
            if (property === 'value' && _.startsWith(express, "{")) {
                // value 属性，以大括号开头的是 Ext 表达式语法，该属性是由 bindValue 解析使用，可以忽略
                return
            }

            if (_.startsWith(express, "{")) {
                if (_.endsWith(express, "}")) {
                    // 剔除花括号
                    express = express.substring(1, express.length - 1)

                    // 检查有没有其他符号
                    if (express.includes('+') || express.includes('-') || express.includes('(') ||
                        express.includes(')') || express.includes('*') || express.includes('/') ||
                        express.includes('{') || express.includes('}') || express.includes(' ')) {
                        console.error('错误表达式:' + express)
                        return
                    }
                    express = "return this." + express + ";"

                } else {
                    console.error('错误表达式:' + express)
                    return
                }
            }

            const stopHandle = this.$watch(() => {
                return runExpress(express, this)
            }, (calcValue) => {
                this[property] = calcValue
            }, {immediate: true})

            this.stopList.push(stopHandle)
        })

        // this.$nextTick(() => {
        //     if (this.vjson.xtype) {
        //         console.timeLog(this._timeId, 'vjson-' + this.vjson.xtype)
        //     } else if (this.vjson.layout) {
        //         console.timeLog(this._timeId, 'layout-' + this.vjson.layout)
        //     } else if (_.isArray(this.vjson)) {
        //         console.timeLog(this._timeId, 'array-' + _.size(this.vjson))
        //     }
        // })
    },
    unmounted() {
        this._destroyed = true
        this.$nextTick(() => {
            this.runEvent('destory')
        })

        // 释放所有 bind 属性绑定
        _.forEach(this.stopList, (handler) => {
            handler()
        })

        const reference = this.vjson.reference
        if (reference) {
            // 在模型中挂接实体类
            if (this.vcxt.scope.$data.refs) {
                delete this.vcxt.scope.$data.refs[reference]
            }
        }
    },
    computed: {
        realValue() {
            // let bindValue = this.bind?.value
            // if (_.startsWith(bindValue, '{') && _.endsWith(bindValue, '}')) {
            //     bindValue = bindValue.substring(1, bindValue.length - 1)
            //     return _.get(this.vcxt.scope.$data, bindValue)
            // }

            return evalGetBind(this, 'value')
        },
        calcClass() {
            return calcClass(this.vjson)
        },

        calcStyle() {
            return calcStyle(this.vjson)
        },

        calcStyleAndWidth() {
            return calcStyleAndWidth(this.vjson)
        },
    },
    methods: {
        getRuntimeCmp,
        _getFormItemBaseRule(vjson) {
            const rules = []
            if (vjson.required) {
                let message
                if (vjson.fieldLabel) {
                    message = '"' + vjson.fieldLabel + '" 不能为空'
                } else {
                    message = '不能为空'
                }
                // rules.push({required: true, message: message, fieldLabel: vjson.fieldLabel, trigger: 'change',})
                rules.push({
                    validator: ({field, fieldLabel, fullField, message, type}, value, callback, kv, opt) => {
                        let ret = true
                        if (typeof value === 'undefined' || value === null) {
                            ret = false
                        } else if (typeof value === 'string' && ('' + value).length <= 0) {
                            ret = false
                        }

                        if (ret) {
                            // 验证通过
                            callback()
                        } else {
                            callback(new Error(message))
                        }
                        return ret
                    }, required: true,
                    message: message, trigger: 'change',
                })
            }

            return rules;
        },
        _onFocus(e) {
            // getListener(this.vjson, 'focus', this.vcxt)(this, this.vcxt.scope, e)
            this.runEvent('focus', ...arguments)
        },
        _onBlur(e) {
            // getListener(this.vjson, 'blur', this.vcxt)(this, this.vcxt.scope, e)
            this.runEvent('blur', ...arguments)
        },

        _onValueChange(value) {
            // let bindValue = this.bind?.value
            // if (_.startsWith(bindValue, '{') && _.endsWith(bindValue, '}')) {
            //     bindValue = bindValue.substring(1, bindValue.length - 1)
            //     _.set(this.vcxt.scope.$data, bindValue, value)
            // }
            evalSetBind(this, 'value', value)
        },

        /**
         * 在运行时，运行 VJson 的对应事件, vjson 对事件的定义有两种方法
         * {
         *     xtype: 'button',
         *     listeners: {
         *         click: '{btn1_click}',   // 自动替换为下面
         *         click: 'this.btn1_click()',  // 直接运行 EVAL
         *     }
         * }
         *
         *
         * @param eventName 事件名称
         * @param args 事件参数
         */
        runEvent(eventName, ...args) {
            runEvent(this.vcxt.scope, this.vjson, eventName, ...args)
        },

    },
}